# -*- coding: utf-8 -*-

import os
import re
import operator

import string
import cgi
import urllib

import time
from datetime import datetime

import wsgiref.handlers

import markdown

from BeautifulSoup import BeautifulSoup

from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext import db
from google.appengine.ext.webapp import template


# When test on localhost , set DEBUG=True.

#DEBUG=True
DEBUG=False


YOUR_APP_NAME='' # input your-app-name
YOUR_GOOGLE_ACCOUNT='foo@bar.com'



BASEURL='http://localhost:8080'
if DEBUG==False :
	BASEURL='http://'+YOUR_APP_NAME+'.appspot.com'









class Note(db.Model): 
	fname = db.StringProperty(multiline=False) 
	fname_prev = db.StringProperty(multiline=False) 
	title = db.TextProperty()
	content = db.TextProperty()
	date = db.DateTimeProperty(auto_now_add=True)
	cdate = db.DateTimeProperty(auto_now_add=True)
	remove = db.BooleanProperty(default=False, required=True)


class MarkdownNote:

	def __init__(self,note):

		self.fname=note.fname
		self.fname_prev=note.fname_prev
		self.fname_next=self.getFnameNext(note)

		self.date=note.date
		self.cdate=note.cdate
		self.content=note.content
		self.html=""

		c=self.content
		if c!=None:
			self.html=markdown.markdown(note.content)

		self.title=self.fname

		soup=BeautifulSoup(self.html)
		h1s=soup('h1')
		if len(h1s)>0:
			self.title=h1s[0].string

	def getFnameNext(self,note):
		notes=Note.gql("WHERE fname_prev = :1 ",note.fname)
		if notes.count()>0:
			return notes[0].fname

		return None

class NoteManager:

	def __init__(self,fname):
		self.fname=fname

	def remove(self):
		notes=Note.gql("WHERE fname = :1 ",self.fname)
		for note in notes:
			note.delete()

	def exists(self):
		notes=Note.gql("WHERE fname = :1 ",self.fname)
		if notes.count()>0:
			return True

		return False

	def put(self,note):
		if self.exists():
			note_=self.get()
			note_.title=note.title
			note_.content=note.content
			note_.date=note.date
			note_.remove=False
			note_.put()

		else :
			notes=Note.gql("ORDER BY cdate DESC LIMIT 1") # get latest note
			if notes.count()>0:
				note.fname_prev=notes[0].fname
			else:
				note.fname_prev=None
			note.put()

	def exists(self):
		if self.get()==None:
			return False

		return True

	def get(self):
		notes=Note.gql("WHERE fname = :1",self.fname)
		if notes.count()>0:
			return notes[0]

		return None

	def create(self):
		note=Note()
		note.fname=self.fname
		note.content="" 
		return note



class NotePage(webapp.RequestHandler): 

	def isHome(self,rpath):
		if rpath=="/":
			return True
		return False

	def isHtml(self,rpath):
		match=re.search("\\.html$",rpath) 
		if match==None:
			return False
		return True

	def stripHtmlSuffix(self,rpath):
		fname=re.sub("\\.html$","",rpath)
		return fname

	def isTxt(self,rpath):
		match=re.search("\\.txt$",rpath) 
		if match==None:
			return False
		return True

	def stripTxtSuffix(self,rpath):
		fname=re.sub("\\.txt$","",rpath)
		return fname

	def isRemove(self,rpath):
		match=re.search("\\.remove$",rpath) 
		if match==None:
			return False
		return True

	def stripRemoveSuffix(self,rpath):
		fname=re.sub("\\.remove$","",rpath)
		return fname

	#def isSpace(self,rpath):
	#	match=re.search("\\.space$",rpath) 
	#	if match==None:
	#		return False
	#	return True

	#def stripSpaceSuffix(self,rpath):
	#	name=re.sub("\\.space$","",rpath)
	#	return name



	def get(self): 
		self.response.headers['Content-Type'] = 'text/html'
		self.response.headers['pragma'] = 'no-cache'
		self.response.headers['Cache-Control'] = 'no-cache, must-revalidate'

		haveToLogin=False

		rpath=( self.request.path )
		if self.isTxt( rpath )==True :
			haveToLogin=True
		elif self.isRemove( rpath )==True :
			haveToLogin=True

		if haveToLogin==True :
			# when txt (edit) and remove mode , have to login the right user.
			user = users.get_current_user()
			if user==None:
				self.redirect(users.create_login_url(self.request.uri))
			if str(user)!=YOUR_GOOGLE_ACCOUNT:
				self.redirect(users.create_login_url(self.request.uri))

		isLogin=False
		url=None
		url_linktext=None
    		if users.get_current_user(): 
			url = users.create_logout_url(self.request.uri) 
			url_linktext = 'Logout' 
			isLogin=True
		else: 
			url = users.create_login_url(self.request.uri) 
			url_linktext = 'Login'



		if self.isHome( rpath )==True :
			notes=Note.gql("WHERE remove = :1 ORDER BY date DESC LIMIT 100",False)

			template_values={
				'is_logged_in' : isLogin,
				'notes' : notes,
				'url': url,
				'url_linktext': url_linktext,
			}
			path = os.path.join(os.path.dirname(__file__), 'home.html')
			self.response.out.write(template.render(path, template_values))

		if self.isRemove( rpath )==True :

			fname = self.stripRemoveSuffix(rpath)
			nm=NoteManager(fname)
			note=nm.get()

			if note:
				# remove flg on
				note.remove=True
				note.put()

			template_values={
				'note': MarkdownNote(note),
				'fname' : fname
			}
			path = os.path.join(os.path.dirname(__file__), 'remove.html')
			self.response.out.write(template.render(path, template_values))


		if self.isHtml( rpath )==True :
			fname = ( self.stripHtmlSuffix(rpath))

			nm=NoteManager(fname)
			note=nm.get()

			if note:
				if note.remove==True :
					template_values={
						'note': MarkdownNote(note),
						'fname' : fname
					}
					path = os.path.join(os.path.dirname(__file__), 'remove.html')
					self.response.out.write(template.render(path, template_values))
					return 


				mdnote = MarkdownNote(note)
				mdhtml = mdnote.html #markdown.markdown( note.content )

				template_values={
					'is_logged_in' : isLogin,
					'note': mdnote,
					'mdhtml': mdhtml,
					'url' : url,
					'url_linktext': url_linktext,
				}
				path = os.path.join(os.path.dirname(__file__), 'view.html')
				self.response.out.write(template.render(path, template_values))

		if self.isTxt( rpath )==True :

			fname=self.stripTxtSuffix(rpath)

			fname=urllib.unquote_plus(fname) # url decode
			fname=re.sub(' ','',fname) # remove space


			nm=NoteManager(fname)
			note=nm.get()
			if note==None:
				note=nm.create()

			if note!=None:
				template_values={
					'is_logged_in' : isLogin,
					'note': note,
					'url': url,
					'url_linktext': url_linktext,
				}
				path = os.path.join(os.path.dirname(__file__), 'edit.html')
				self.response.out.write(template.render(path, template_values))





#RE_DATE=re.compile('\\{date:(.*)\\}')
#RE_CDATE=re.compile('\\{cdate:(.*)\\}')
#RE_MDATE=re.compile('\\{mdate:(.*)\\}')

class Save(webapp.RequestHandler): 

#	def getdatetime(self,content):
#		dt=self._getdatetime(content,RE_MDATE)
#		if dt!=None:
#			return dt
#
#		dt=self._getdatetime(content,RE_CDATE)
#		if dt!=None:
#			return dt
#
#		dt=self._getdatetime(content,RE_DATE)
#		if dt!=None:
#			return dt
#
#
#		return datetime.now()
#
#	def _getdatetime(self,content,myre):
#		cdate=None
#
#		r=myre.findall(content)
#		if len(r)>0 :
#			cdate=r[0]
#
#		if cdate!=None:
#			st=time.strptime(cdate,'%Y-%m-%d')
#			dt=datetime(st.tm_year, st.tm_mon, st.tm_mday)
#
#			return dt
#			
#		return None


	def post(self): 

		user = users.get_current_user()
		if user and str(user)==YOUR_GOOGLE_ACCOUNT:

			note=Note()
			note.fname=self.request.get('fname')
			note.content=self.request.get('content')
			note.title=MarkdownNote(note).title

			#note.date=self.getdatetime(note.content)
			note.date=datetime.now()

			NoteManager(note.fname).put(note)

			#self.redirect('/')
			self.redirect(note.fname+".html")


#
# base class for maintenance page class
#
class BasePage(webapp.RequestHandler): 

	def getuser(self):
		user = users.get_current_user()
		if user==None:
			return self.__getuser()

		return user

	def __getuser(self):
		email=YOUR_GOOGLE_ACCOUNT

		user = users.User(email)
		return user



RE_LABEL_IN_TITLE=re.compile('\\(([^\\)]*)\\)$')

#
# output note info for HyperEstraier draft format
#
class InfoPage(BasePage): 

	def get(self): 
		self.response.headers['Content-Type'] = 'text/html'
		self.response.headers['pragma'] = 'no-cache'
		self.response.headers['Cache-Control'] = 'no-cache, must-revalidate'

		fname=cgi.escape(self.request.get('fname'))
		if fname==None:
			return 

		notes=Note.gql("WHERE fname = :1 LIMIT 1",fname)

		for note in notes:
			self.response.out.write('{')
			self.response.out.write('"uri":"'+BASEURL+note.fname+'.html"')
			self.response.out.write(',')
			self.response.out.write('"title":"'+note.title+'"')
			self.response.out.write(',')
			self.response.out.write('"mdate":"'+str(note.date.isoformat())+'"')
			self.response.out.write(',')
			self.response.out.write('"cdate":"'+str(note.cdate.isoformat())+'"')

			categories=self.getCategories(note)
			if len(categories)>0:
				self.response.out.write(',')

				self.response.out.write('"category":')
				self.response.out.write('"')
				for c in categories:
					self.response.out.write(c+',')
				self.response.out.write('"')

			self.response.out.write('}')

	def getCategories(self,note):
		r=RE_LABEL_IN_TITLE.findall(note.title)
		if r==None :
			return []

		if len(r)>0 :
			labels=[]
			for token in r[0].split(','):
				labels.append(token)

			return labels

		return []


#
# output note lastmodified info
#
class LastModifiedPage(BasePage): 

	def get(self): 
		self.response.headers['Content-Type'] = 'text/html'
		self.response.headers['pragma'] = 'no-cache'
		self.response.headers['Cache-Control'] = 'no-cache, must-revalidate'

		fname=cgi.escape(self.request.get('fname'))
		if fname==None:
			return 

		notes=Note.gql("WHERE fname = :1 LIMIT 1",fname)

		for note in notes:
			self.response.out.write('{')
			self.response.out.write('"mdate":"'+str(note.date.isoformat())+'"')
			self.response.out.write('}')


#
# output note content dump
#
class DumpPage(BasePage): 

	def get(self): 
		self.response.headers['Content-Type'] = 'text/html'
		self.response.headers['pragma'] = 'no-cache'
		self.response.headers['Cache-Control'] = 'no-cache, must-revalidate'

		fname=cgi.escape(self.request.get('fname'))
		if fname==None:
			return 

		notes=Note.gql("WHERE fname = :1 LIMIT 1",fname)

		for note in notes:
			if note.remove==False:
				self.response.out.write(note.content)
			else :
				self.response.out.write("")

class RenamePage(BasePage): 

	def get(self): 
		self.response.headers['Content-Type'] = 'text/html'
		self.response.headers['pragma'] = 'no-cache'
		self.response.headers['Cache-Control'] = 'no-cache, must-revalidate'

		fname=cgi.escape(self.request.get('fname'))
		newfname=cgi.escape(self.request.get('newfname'))

		# url encode
		fname=urllib.quote(fname)
		newfname=urllib.quote(newfname)

		#self.response.out.write( fname )
		#self.response.out.write( newfname )

		ok=False
		if len(fname)>0 and len(newfname)>0 :
			notes=Note.gql("WHERE fname = :1 LIMIT 1",fname)
			self.response.out.write( notes.count() )
			if notes.count()>0 :
				notes=Note.gql("WHERE fname = :1 LIMIT 1",newfname)
				if notes.count()<1 :
					ok=True
				
		if ok==True:
			notes=Note.gql("WHERE fname = :1 LIMIT 1",fname)
			if notes.count()>0 :
				note=notes[0]
				note.fname=newfname
				note.put()

				notes=Note.gql("WHERE fname_prev = :1 LIMIT 1",fname)
				if notes.count()>0 :
					note=notes[0]
					note.fname_prev=newfname
					note.put()

			self.response.out.write('OK')

		else:
			self.response.out.write('NG')

#
# output notechain info
#
class NoteChainPage(BasePage): 

	def get(self): 

		self.response.headers['Content-Type'] = 'text/html'
		self.response.headers['pragma'] = 'no-cache'
		self.response.headers['Cache-Control'] = 'no-cache, must-revalidate'

		fname=cgi.escape(self.request.get('fname'))

		if len(fname)<1 :
			notes=Note.gql("ORDER BY cdate DESC LIMIT 1") # get latest note
			if notes.count()>0 :
				note=notes[0]

				self.response.out.write('{')
				self.response.out.write('"status":"OK"')

				self.response.out.write(',')
				self.response.out.write('"current":"'+note.fname+'"')
				self.response.out.write('}')

			return 

		else :
			notes=Note.gql("WHERE fname = :1 LIMIT 1",fname)

			if notes.count()>0 :
				note=MarkdownNote(notes[0])

				self.response.out.write('{')
				self.response.out.write('"status":"OK"')

				if note.fname_prev!=None:
					self.response.out.write(',')
					self.response.out.write('"previous":"'+note.fname_prev+'"')

				if note.fname!=None:
					self.response.out.write(',')
					self.response.out.write('"current":"'+note.fname+'"')

				if note.fname_next!=None:
					self.response.out.write(',')
					self.response.out.write('"next":"'+note.fname_next+'"')

				self.response.out.write('}')

			else :
				self.response.out.write('{')
				self.response.out.write('"status":"Error"')
				self.response.out.write('}')




def main(): 
	application = webapp.WSGIApplication(
		[
			('/Rename', RenamePage),
			('/NoteChain', NoteChainPage),
			('/LastModified',LastModifiedPage),
			('/Info',InfoPage),
			('/Dump', DumpPage) ,
			('/Save', Save) ,
			('/.*', NotePage) ], debug=DEBUG) 

	wsgiref.handlers.CGIHandler().run(application)

if __name__ == "__main__": 
	main()

